﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Design;
using System.ComponentModel;
using System.Drawing.Design;
using EnvDTE;
using System.Windows.Forms;
using System.Reflection;

namespace SPVisualDev.VSAddin.Dialogs.PropertySheets
{
    internal class EventClassCollectionEditor : UITypeEditor
    {
        private IPropertySheet m_owner_sheet;
        private string m_property_name;
        private object m_init_value;
        private string m_default_code_folder;
        private string m_default_namespace;
        private object m_instance;

        public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            return UITypeEditorEditStyle.Modal;
        }

        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            m_instance = context.Instance;
            m_owner_sheet = context.Instance as IPropertySheet;
            m_property_name = context.PropertyDescriptor.Name;
            m_init_value = value;

            if (m_instance is PropSheetListTemplate)
            {
                PropSheetListTemplate p = m_instance as PropSheetListTemplate;
                if (string.IsNullOrEmpty(p.Name))
                    throw new Exception("You must enter a list template name first.");

                if (p.Type == 0 || p.Type == -1)
                    throw new Exception("You must assign a list tempalte type first.");
            }
            if (m_instance is PropSheetContentType)
            {
                PropSheetContentType p = m_instance as PropSheetContentType;
                if (string.IsNullOrEmpty(p.Name.RawString))
                    throw new Exception("You must enter a content type name first.");

                if (string.IsNullOrEmpty(p.ID))
                    throw new Exception("You must assign a content type ID first.");
            }

            PropertyInfo piOwnerGrid = context.GetType().GetProperty("OwnerGrid");
            PropertyGrid grid = piOwnerGrid.GetValue(context, null) as PropertyGrid;
            DialogFeatureEditor featureEditor = grid.ParentForm as DialogFeatureEditor;
            if (featureEditor != null)
            {
                m_default_code_folder = featureEditor.DefaultCodeFolder;
                m_default_namespace = featureEditor.DefaultCodeNamespace;
            }

            if (!Common.HasAssemblyReferenced(m_owner_sheet.ParentFeatureFolder.ContainingProject, "Microsoft.Sharepoint"))
            {
                string msg = "You need to add a reference to Microsoft.Sharepoint.dll in order to add event receivers to this project. If you are connected to a remote server, you can import this dll by right clicking on the project node in the solution explorer and choose 'Import SP dlls' from the context menu.";
                MessageBox.Show(msg, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

                return value;
            }

            bool bMustBuild = false;

            if (string.IsNullOrEmpty((m_instance as IPropertySheet).ElementInfo.Manager.AssemblyStrongName))
                bMustBuild = true;
            
            bool hasKeyFile = Common.ProjectHasKeyFileAssigned(m_owner_sheet.ParentFeatureFolder.ContainingProject);
            if (!hasKeyFile)
            {
                string msg = "You need to assign a key pair file to the project so it can be signed and have a valid strong name. Click OK if you want to import an existing or create a new.";

                DialogResult result = MessageBox.Show(msg, "Prompt", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
                if (result != DialogResult.OK)
                    return value;

                using (DialogSNKSelector dialog = new DialogSNKSelector(m_owner_sheet.ParentFeatureFolder.ContainingProject))
                {
                    result = dialog.ShowDialog();
                    if (result != DialogResult.OK)
                        return value;

                    if (dialog.ProjectExplorer.TreeView.SelectedNode == null ||
                        dialog.ProjectExplorer.TreeView.SelectedNode.Tag == null)
                        throw new Exception("No key file selected.");

                    ProjectItem key_item = dialog.ProjectExplorer.TreeView.SelectedNode.Tag as ProjectItem;
                    if (key_item == null)
                        throw new Exception("No key file selected.");

                    if (key_item.Kind != Constants.vsProjectItemKindPhysicalFile)
                        throw new Exception("No key file selected.");

                    key_item.ContainingProject.Properties.Item("AssemblyOriginatorKeyFile").Value = Common.GetProjectItemPath(key_item);
                    key_item.ContainingProject.Properties.Item("SignAssembly").Value = true;
                    key_item.ContainingProject.Properties.Item("AssemblyOriginatorKeyFileType").Value = 1;


                    Common.SetProjectGlobalConfigKey(key_item.ContainingProject, "AssemblyBuildType", "GAC", true);

                    bool isProjectUnderSCC = key_item.DTE.SourceControl.IsItemUnderSCC(key_item.ContainingProject.FullName);
                    if (isProjectUnderSCC)
                    {
                        bool isProjectCheckedOut = key_item.DTE.SourceControl.IsItemCheckedOut(key_item.ContainingProject.FullName);
                        if (!isProjectCheckedOut)
                            key_item.DTE.SourceControl.CheckOutItem(key_item.ContainingProject.FullName);
                    }

                    key_item.ContainingProject.Save(key_item.ContainingProject.FullName);
                }

                bMustBuild = true;

            }

            if (bMustBuild)
            {
                MessageBox.Show("SPVisualDev must build the project now to be able to extract the public key token. Click OK to proceed.", "Prompt", MessageBoxButtons.OK, MessageBoxIcon.Information);

                bool b = Common.BuildProject(m_owner_sheet.ParentFeatureFolder.ContainingProject, true, true);
                if (!b)
                {
                    throw new Exception("Build failed. See the build output window for more details.");
                }
            }

            Project project = m_owner_sheet.ParentFeatureFolder.ContainingProject;

            string startUpFolder;
            string suggestedName = string.Empty;

            if (m_default_code_folder.StartsWith("<Feature folder>\\", StringComparison.OrdinalIgnoreCase))
            {
                startUpFolder = Common.GetProjectItemPath(m_owner_sheet.ParentFeatureFolder, true) + "\\CodeFiles";
            }
            else
            {
                startUpFolder = m_default_code_folder.Replace("<Project root>\\", "");
            }

            if (m_instance is PropSheetListTemplate)
            {
                PropSheetListTemplate p = m_instance as PropSheetListTemplate;
                if (string.IsNullOrEmpty(p.Name))
                {
                    suggestedName = "ListTemplate_" + p.Type.ToString();
                }
                else
                {
                    suggestedName = p.Name;
                }
            }
            else if (m_instance is PropSheetContentType)
            {
                PropSheetContentType p = m_instance as PropSheetContentType;

                suggestedName = "ContentType";
                if (ResourceHelper.IsResourceString(p.Name.RawString))
                {
                    if (!string.IsNullOrEmpty(p.Name.RawString))
                        suggestedName += "_" + ResourceHelper.ParseResourceKeyFromRawString(p.Name.RawString);
                }
                else
                {
                    if (!string.IsNullOrEmpty(p.Name.RawString))
                        suggestedName += "_" + p.Name.RawString;
                }

            }


            using (DialogEventClassSelector dialog = new DialogEventClassSelector(project))
            {
                dialog.BaseClassesConstraint = new List<string>(new string[] { "SPItemEventReceiver", "SPListEventReceiver" });
                dialog.StartupCodeFolder = startUpFolder;
                dialog.DefaultNamespace = m_default_namespace;
                dialog.SuggestedName = suggestedName;
                dialog.CodeClassesList = value as List<CodeClass>;

                DialogResult result = dialog.ShowDialog();
                if (result != DialogResult.OK)
                    return value;

                if (m_instance is PropSheetListTemplate)
                {
                    (m_instance as PropSheetListTemplate).EventReceiverClasses = dialog.CodeClassesList;
                    m_owner_sheet.ElementInfo.Manager.GenerateEventReceivers();
                }
                else
                {
                    (m_instance as PropSheetContentType).EventReceiverClasses = dialog.CodeClassesList;
                    m_owner_sheet.ElementInfo.Manager.GenerateEventReceivers();
                }

                return dialog.CodeClassesList;
            }
        }

    }

}
